#include "StdAfx.h"
#include "CodeFactory.h"

#include <assert.h>

static const int S_MSGBUF_MAX = 2048;

#define getMessage( msg, msglen, pat ) \
do \
{ \
	va_list ap; \
	memset( msg, 0, msglen ); \
	va_start( ap, pat ); \
	vsnprintf( msg, msglen - 1, pat, ap ); \
	va_end( ap ); \
}while( false )

CodeFactory::CodeFactory(void)
	: m_indent( 0 )
	, m_indentchar( '\t' )
	, m_beginline_flag( false )
{
}

CodeFactory::~CodeFactory(void)
{
}

void CodeFactory::appendLine()
{
	m_buffer << std::endl;
}

void CodeFactory::appendLine( const char* pattern, ... )
{
	assert( beginlineflag() == false );
	char msg[S_MSGBUF_MAX] = {'\0'};
	getMessage( msg, S_MSGBUF_MAX, pattern );	
	appendIndent();
	m_buffer << msg;
	appendLine();
}

void CodeFactory::appendIndent()
{
	for( int i = 0; i < indent(); ++i )
	{
		m_buffer << indentchar();	
	}
}

void CodeFactory::beginLine()
{
	assert( beginlineflag() == false );
	beginlineflag( true );
	appendIndent();
}


void CodeFactory::endLine()
{
	assert( beginlineflag() );
	beginlineflag( false );
	appendLine();
}

void CodeFactory::append( const char value )
{
	assert( beginlineflag() );
	m_buffer << value;
}

void CodeFactory::append( const char* pattern, ... )
{
	assert( beginlineflag() );
	char msg[S_MSGBUF_MAX] = {'\0'};
	getMessage( msg, S_MSGBUF_MAX, pattern );	
	m_buffer << msg;
}

bool CodeFactory::padRight( const int totalwidth )
{
	return codePad( totalwidth, 4 );
}

bool CodeFactory::codePad( const int totalwidth, const int tabsize )
{
	assert( beginlineflag() );
	int len = 0;
	size_t pos1 = m_buffer.str().find_last_of( "\n" );
	size_t pos2 = m_buffer.str().find_last_of( "\t" );
	size_t pos = max( pos1, pos2 );
	for( ; pos < m_buffer.str().size(); ++pos )
	{
		char c = m_buffer.str().at( pos );
		if( c == '\t' )
			len += tabsize;
		else
			len += 1;
	}
	if( len < totalwidth )
	{
		for( int i = 0; i < totalwidth - len; ++i )
		{
			m_buffer << " ";
		}
		return true;
	}
	return false;
}